package com.otp.webapp.action.util;

import java.util.List;

import org.apache.commons.math3.distribution.NormalDistribution;

import com.otp.model.test.instance.TestInstanceScore;
import com.otp.model.test.template.Item;
import com.otp.model.test.template.TestTemplate;
import com.otp.webapp.action.AdaptiveMethods;
import com.otp.webapp.action.AnsweredItem;

public class TestScoreUtil {

	/**
	 * Calculate test algorithm does not depend on the defaultAlgo string
	 */

	public static TestInstanceScore simpleSumsScores(List<AnsweredItem> items){
		//All items must belong to the same test template!!!
		//DisplayTestResult result = new DisplayTestResult();
		TestInstanceScore testInstanceScore = new TestInstanceScore();
		
		Double maxScore=0.0;
		Double rawScore=0.0;
		Double percentage=-1.;
		Double zScore=0.0;
		Double percentile;
		Double sten;
		
		TestTemplate subtest = items.get(0).getItem().getTestTemplate();
		testInstanceScore.setTestTemplate(subtest);
		testInstanceScore.setTestInstance(items.get(0).getTestInstance());
		
		for(AnsweredItem ans:items){
			Item itm = ans.getItem();
			maxScore+=itm.getMaxScore();
			rawScore+=ans.getScore();				
		}
		percentage=rawScore/maxScore;
		zScore=(rawScore-subtest.getMean())/subtest.getStandardDeviation();
		percentile = calculatePercentileRankNormed(zScore, 0., 1.);
		sten = 2*zScore + 5.5;
		if (sten > 10) sten = 10.;
		if (sten < 1) sten = 1.;

		testInstanceScore.setMaxScore(maxScore);
		testInstanceScore.setRawScore(rawScore);
		testInstanceScore.setPercentageScore(percentage);
		testInstanceScore.setZetaScore(zScore);
		testInstanceScore.setPercentileRank(percentile);
		testInstanceScore.setStenScore(sten);
		
		return testInstanceScore;
	}

	public static TestInstanceScore adaptiveTestScore(AdaptiveMethods adaptParams){

		TestInstanceScore testInstanceScore = new TestInstanceScore();
		Double maxScore=0.0;
		Double rawScore=0.0;
		Double percentage=-1.;
		Double thetaEAP;
		Double thetaML;
		Double thetaMAP;
		Double errorEAP;
		Double errorML;
		Double errorMAP;		
		Double percentile;
		Double sten;

		testInstanceScore.setTestInstance(adaptParams.getTestInstance());
		testInstanceScore.setTestTemplate(adaptParams.getTestTemplate());
		List<AnsweredItem> ansList = adaptParams.getAnsdItems();

		for(AnsweredItem ans:ansList){
			Double maxPartial = ans.getItem().getMaxScore();
			Double partialScore = ans.getScore();
			if(maxPartial==null) {maxScore=null; break;}
			if(partialScore==null) {partialScore=null; break;}
			maxScore+=maxPartial;
			rawScore+=partialScore;			
		}
		
		if(maxScore!=null&&rawScore!=null) percentage=rawScore/maxScore;
		else percentage = null;
				
		thetaEAP=adaptParams.getAbilityEst();
		thetaML=adaptParams.getAbilityML();
		thetaMAP=adaptParams.getAbilityMAP();

		errorEAP=adaptParams.getErrorEAP();
		errorML=adaptParams.getErrorML();
		errorMAP=adaptParams.getErrorMAP();

		if(thetaEAP!=null){
		percentile = calculatePercentileRankNormed(thetaEAP, 0., 1.);
		sten = 2*thetaEAP + 5.5;
		}
		else if(thetaMAP!=null){
			percentile = calculatePercentileRankNormed(thetaMAP, 0., 1.);
			sten = 2*thetaMAP + 5.5;
		}
		else if(thetaML!=null){			
				percentile = calculatePercentileRankNormed(thetaML, 0., 1.);
				sten = 2*thetaML + 5.5;	
		}
		else {System.out.println("ERROR: All adaptive metrics are null"); return null;}
		
		if(sten<1) sten=1.;
		if(sten>10) sten=10.;
		
		testInstanceScore.setMaxScore(maxScore);
		testInstanceScore.setRawScore(rawScore);
		testInstanceScore.setPercentageScore(percentage);
		testInstanceScore.setThetaEAP(thetaEAP);
		testInstanceScore.setThetaML(thetaML);
		testInstanceScore.setThetaMAP(thetaMAP);
		testInstanceScore.setErrorEAP(errorEAP);
		testInstanceScore.setErrorML(errorML);
		testInstanceScore.setErrorMAP(errorMAP);
		testInstanceScore.setPercentileRank(percentile);
		testInstanceScore.setStenScore(sten);

		return testInstanceScore;
	}

	//Should be moved to mathematicalFunctions, but I cannot import NormalDistribution  //TODO
	public static Double calculatePercentileRankNormed(Double rawScoreTest, Double mean,
			Double standardDeviation) {
		Double normedScore=0.0;

		NormalDistribution nd = new NormalDistribution(mean, standardDeviation);
		normedScore = nd.cumulativeProbability(rawScoreTest);

		return normedScore;
	}

}
